﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Web.Mvc;
using System.Web;

namespace DNA.Mvc.Installation
{
    public class InstallationService : CommandContainer<InstallerBase,InstallerFilter>
    {
        private IDependencyResolver _resolver = null;
        private IEnumerable<InstallerBase> _installers = null;

        public InstallationService()
        {
            _resolver = DependencyResolver.Current;
        }

        public InstallationService(IDependencyResolver resolver)
        {
            if (resolver != null)
                _resolver = resolver;
        }

        public void Install(string filename, HttpContextBase httpContext = null, object settings = null)
        {
            Initialize(filename);
            var context = new InstallationContext(settings) { HttpContext = httpContext };
            Invoke(context);
        }

        public List<InstallerBase> Installers
        {
            get
            {
                return InnerItems;
            }
        }

        protected override void OnCommandError(CommandErrorEventArgs e)
        {
            var installerName="unknow";
            var installer = e.Context.Command as InstallerBase;

            if (installer != null)
                installerName = installer.Name;
            string msg = string.Format("Unhandling error occur during installation.Installer name: \"{0}\".", installerName);

            e.Context.Trace.Warn("Critical", msg, e.ErrorInfo);
        }

        protected override void OnCommandExecute(CommandExecuteEventArgs e)
        {
            var installerName = "unknow";
            var installer = e.Context.Command as InstallerBase;

            if (installer != null)
                installerName = installer.Name;
            string msg = string.Format("Executing installer \"{0}\" ...", installerName);
            
            e.Context.Trace.Write(msg);
        }

        private void Initialize(string filename)
        {
            //try
            //{
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(filename);
            foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
            {
                //var attrs = new Dictionary<string, string>();

                if ((node.Attributes["name"] == null) || string.IsNullOrEmpty(node.Attributes["name"].Value))
                {
                    // WriteLog("Installation configuation error, installer must be have a name.\n\t" + node.OuterXml);
                    throw new Exception("Installation configuation error, installer must be have a name.\n\t" + node.OuterXml);
                    //continue;
                }

                string _name = node.Attributes["name"].Value;

                var installer = GetInstaller(_name);
                if (installer == null)
                {
                    throw new Exception("Installer not found.name=" + _name);
                    //WriteLog("Installer not found.name=" + _name);
                    //continue;
                }
                //installer.HttpContext = HttpContext;
                installer.ExecutionPath = System.IO.Path.GetDirectoryName(filename);
                installer.ConfigXml = node.InnerXml;
                this.InnerItems.Add(installer);
            }

            //}
            //catch (Exception e)
            //{
            //    WriteLog(e.Message);
            //}
        }

        public InstallerBase GetInstaller(string name)
        {
            if (_installers == null)
                _installers = _resolver.GetServices<InstallerBase>();
            return _installers.FirstOrDefault(s => s.Name.Equals(name));
        }
    }

}
